<template>
  <div>
    <div class="upgrade-box">
      <div class="frame">
        <div class="text-center upgrade-title">
          <img
            src="@/static/img/top/upgrade-title.png"
            class="upgrade-title-img"
          />
          <div class="tip">
            <img src="@/static/img/top/illustrate.png" />
            玩法说明
            <div class="hot-to-play">
              <p v-for="text in howToPlayTexts" :key="text">{{ text }}</p>
            </div>
          </div>
          <div class="tip tipHis" @click="handleToTopHistory">
            历史记录
          </div>
        </div>
        <div class="compass-box-mobile">
          <compass-box
            :rate="rate"
            :spend="spend"
            :point="upgradePoint"
            :animation-flag="animationFlag"
          ></compass-box>
        </div>

        <div class="frame-content">
          <div class="top-skin">
            <template v-if="!upgradeSkin">
              <div class="top-skin-text">请选择升级目标</div>
              <div
                class="top-skin-button btn-add"
                @click="handleClickButton"
                v-loading="getConfigLoading"
              ></div>
            </template>

            <template v-else>
              <div class="upgrade-skin">
                <div class="bac-icon">
                  <div
                    class="bac"
                    :style="{
                      'box-shadow':
                        upgradeSkin.rarity_color + ' 0px 0px 60px 60px',
                    }"
                  ></div>
                </div>
                <img :src="upgradeSkin.image_url" />
              </div>
              <v-btn
                class="upgrade-btn"
                variant="outlined"
                size="small"
                @click="openSkinDialog"
                v-if="!upgradeLoading"
                >更换目标</v-btn
              >
            </template>
          </div>

          <compass-box
            class="compass-box-pc"
            :rate="rate"
            :spend="spend"
            :point="upgradePoint"
            :animation-flag="animationFlag"
          ></compass-box>

          <div class="top-skin">
            <div class="top-skin-button btn-unknow"></div>
          </div>
        </div>

        <div class="rate-wrapper">
          <div class="rate-text">
            <div>
              <span>成功率({{ rate }}%)</span>
              <span>[1, {{ n }}]</span>
            </div>
            <div>
              <span>失败率{{ failRate }}%</span>
              <span>[{{ n + 1 }}, 10000]</span>
            </div>
          </div>

          <el-slider
            v-model="rate"
            :marks="marks"
            :max="100"
            :show-tooltip="false"
            @input="onRateChahnge"
            class="top-slider"
            :disabled="upgradeLoading"
          ></el-slider>
        </div>

        <div class="mt-10 upgrade-bottom">
          <div
            class="d-flex align-center"
            style="width: 261px; margin-left: 60px"
          >
            <el-input
              :placeholder="
                !upgradeSkin
                  ? '范围[3-100000]'
                  : '范围[' + minCoins + '-' + maxCoins + ']'
              "
              v-model="coins"
            ></el-input>
            <v-btn
              color="#9D7EFF"
              class="text-white"
              :disabled="upgradeLoading"
              @click="changeRate"
              >设置</v-btn
            >
          </div>

          <div style="width: 266px; margin-left: 86px; margin-right: 65px">
            <v-btn
              block
              color="#9D7EFF"
              class="text-white"
              :disabled="!upgradeSkin || upgradeLoading"
              @click="upgrade"
              >{{ upgradeLoading ? "升级中" : "开始" }}</v-btn
            >
          </div>

          <div class="top-setting">
            <span
              class="upgrade-button"
              @click="isShowUpgradeGuideDialog = true"
              >升级指南</span
            >
            <v-btn
              color="#9D7EFF"
              class="text-white"
              @click="changeAnimationFlag"
              :disabled="upgradeLoading"
              >{{ animationFlag ? "关闭" : "开启" }}动画</v-btn
            >
            <v-btn
              color="#9D7EFF"
              class="text-white"
              :disabled="upgradeLoading"
              @click="musicFlag = !musicFlag"
              >{{ musicFlag ? "关闭" : "开启" }}音效</v-btn
            >
            <v-btn
              color="#9D7EFF"
              class="text-white"
              @click="reset"
              :disabled="upgradeLoading"
              >重置</v-btn
            >
          </div>
        </div>
      </div>
    </div>

    <skin-dialog
      v-model="isShowSkinDialog"
      @submit="handleUpgradeSkin"
    ></skin-dialog>

    <result-dialog
      v-model="isShowResultDialog"
      @close="handleCloseResultDialog"
      :skin="upgradeSkin"
      :result="upgradeResult"
      :backpack-id="upgradeBackpackId"
      :point="upgradePoint"
    ></result-dialog>

    <v-dialog v-model="isShowUpgradeGuideDialog">
      <div class="upgrade-guide">
        <div class="upgrade-guide-title">
          升级指南
          <i
            class="el-icon-close"
            @click="isShowUpgradeGuideDialog = false"
          ></i>
        </div>
        <p v-for="text in upgradeGuidTexts" :key="text">{{ text }}</p>
      </div>
    </v-dialog>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref, computed } from "vue";
import { useStore } from "@/store";
import SkinDialog from "./components/SkinDialog.vue";
import TopService from "@/services/TopService";
import ResultDialog from "./components/ResultDialog.vue";
import { ElMessage } from "element-plus";
import CompassBox from "./components/CompassBox.vue";
import { sleep } from "@/utils";
import {useRouter} from "vue-router";

export interface SkinItem {
  id: number;
  exterior_name: string;
  image_url: string;
  short_name: string;
  price: number;
  rarity_color: string;
  price_info: {
    price: number;
    quantity: number;
    autoDeliverPrice: number;
    autoDeliverQuantity: number;
    manualDeliverPrice: number;
    manualQuantity: number;
  };
}

export const upgradeAnimationDuraction = 6000;
const musicTop = new Audio("/media/top.mp3");
const musicSuccess = new Audio("/media/upgrade-success.mp3");
const musicFail = new Audio("/media/upgrade-fail.mp3");

export default defineComponent({
  setup() {
    const router = useRouter();
    const minRate = 5;
    const maxRate = 75;
    const MIN_COINS = 3;

    const defaultRate = 20;

    const rate = ref(defaultRate);
    const isShowSkinDialog = ref(false);
    const isShowResultDialog = ref(false);
    const isShowUpgradeGuideDialog = ref(false);
    const upgradeSkin = ref<SkinItem | null>(null);

    const store = useStore();
    const upgradeProfitRate = ref(0);
    const getConfigLoading = ref(false);
    const upgradeLoading = ref(false);
    const upgradeResult = ref(false);
    const upgradeBackpackId = ref(0);
    const upgradePoint = ref(0);
    const coins = ref<string | number>("");

    const minCoins = computed(() => {
      const n = computedCost(minRate);
      return n < MIN_COINS ? MIN_COINS : n;
    });
    const maxCoins = computed(() => computedCost(maxRate));

    const setUpgradeProfitRate = (val: string) => {
      upgradeProfitRate.value = Number(val) / 100;
    };

    const computedCost = (r: number) => {
      const skin = upgradeSkin.value;
      if (!skin) return 0;
      let n = skin.price + skin.price * upgradeProfitRate.value;
      n = n * (r / 100);
      return Number(n.toFixed(2));
    };

    const spend = computed(() => {
      const spend = computedCost(rate.value);
      if (spend && spend < MIN_COINS) {
        rate.value = getRateByCoins(MIN_COINS);
        return computedCost(rate.value);
      }
      return spend;
    });

    const getUpgradeProfitRate = (): Promise<void> => {
      return new Promise((resolve, reject) => {
        if (store.getters.upgrade_profit_rate) {
          setUpgradeProfitRate(store.getters.upgrade_profit_rate);
          resolve();
        } else {
          getConfigLoading.value = true;
          store
            .dispatch("getUpgradeProfitRate")
            .then((val) => {
              if (val) {
                setUpgradeProfitRate(val);
                resolve();
              } else {
                reject("invalid value");
              }
            })
            .catch(reject)
            .finally(() => (getConfigLoading.value = false));
        }
      });
    };

    const playTopMusic = (): Promise<any> => {
      return new Promise((resolve) => {
        musicTop.play();
        musicTop.onended = resolve;
        // 最多延迟500毫秒
        setTimeout(resolve, upgradeAnimationDuraction + 500);
      });
    };

    const upgrade = () => {
      const skin = upgradeSkin.value;
      if (!skin) return;

      const { id } = skin;
      upgradeLoading.value = true;
      musicSuccess.pause();
      musicFail.pause();

      TopService.upgrade({
        skin_id: id,
        range: rate.value,
      })
        .then(async (response) => {
          if (response.data.code === 0) {
            console.log("升级成功");
            const { point, result, backpack_id } = response.data.data;
            let hasValue;
            const setPoint = () => {
              if (!hasValue) {
                upgradePoint.value = point;
                hasValue = true;
              }
            }
            if (animationFlag.value) {
              if (musicFlag.value) {
                // 动效播放后再加载动画
                musicTop.onplay = setPoint;
                setTimeout(setPoint, 1000);
                await playTopMusic();
              } else {
                setPoint();
                await sleep(upgradeAnimationDuraction);
              }
            } else {
              setPoint();
            }

            if (musicFlag.value) {
              if (result) {
                musicSuccess.currentTime = 0;
                musicSuccess.play();
              } else {
                musicFail.currentTime = 0;
                musicFail.play();
              }
            }
            upgradeResult.value = result;
            upgradeBackpackId.value = backpack_id;
            isShowResultDialog.value = true;
            store.dispatch("getUserInfo");
          } else {
            console.log("升级失败", response.data);
          }
        })
        .finally(() => {
          upgradeLoading.value = false;
        });
    };

    const getRateByCoins = (coins: number) => {
      let result =
        (coins / (upgradeSkin.value!.price * (1 + upgradeProfitRate.value))) *
        100;
      if (Math.ceil(result) !== result) {
        result = Number(result.toFixed(2));
      }
      return result;
    };

    const musicFlag = ref(true);
    const animationFlag = computed(() => {
      return store.getters.upgradeLoadingTime > 0;
    });
    const changeAnimationFlag = () => {
      const val = animationFlag.value ? 0 : upgradeAnimationDuraction;
      store.commit("setUpgradeLoadingTime", val);
    };

    if (!animationFlag.value) {
      changeAnimationFlag();
    }

    const openSkinDialog = () => (isShowSkinDialog.value = true);
    const reset = () => {
      upgradeSkin.value = null;
      upgradePoint.value = 0;
      coins.value = "";
      rate.value = defaultRate;
    };

    return {
      rate,
      upgradeSkin,
      marks: new Array(11)
        .fill(0)
        .map((_, i) => i * 10)
        .reduce((marks, val) => {
          marks[val] = val.toString();
          return marks;
        }, {}),
      getConfigLoading,
      upgradeLoading,
      upgradeResult,
      spend,
      coins,
      minCoins,
      maxCoins,
      upgradeBackpackId,
      upgradePoint,

      onRateChahnge: (val) => {
        if (val < minRate) {
          rate.value = minRate;
        } else if (val > maxRate) {
          rate.value = maxRate;
        }
      },
      n: computed(() => Math.floor((rate.value / 100) * 10000)),
      failRate: computed(() => {
        let failRate: string | number = 100 - rate.value;
        if (Math.ceil(failRate) !== failRate) {
          failRate = failRate.toFixed(2);
        }
        return failRate;
      }),
      isShowSkinDialog,
      isShowResultDialog,
      isShowUpgradeGuideDialog,
      animationFlag,
      musicFlag,
      howToPlayTexts:
        `1.玩家选择升级物品，升级物品不能少于10T币，玩家投入不能少于3硬币。
2玩家在决定好升级物品后，可以选择硬币数量.系统会自动生成升级概率;也可以选择升级成功率，由系统自动计算所需硬币的投入。用户选择完成后，点击开始游戏，根据最终落点值决定结果为获得升级物品或者保底物品。
3.指针停留在蓝色区域代表升级成功，空白区域则代表升级失败，升级成功率取决于不同的饰品及硬币投入量，请玩家谨慎选择。
4.升级结果可以在个人中心查询。
5.由于网站采用的纯随机的均匀分布，绝对公平，所以建议用户不要在消费过程中频繁修改成功率，因为这样相反回因此失去一些机会。
6.ofskins平台于前端开箱动画可能因部分未知错误导致显示出错，如您不幸遭遇上述情况（譬如动画结束指针停留于蓝色区域但结果显示升级失败）请您以最终结果为准。或者，我们建议您使用“跳过动画”选项，避免不必要的困扰。
7.ofskins平台中显示的累计账户余额可能与ofskins平台服务器端存在统计差异，实际账户余额以服务器端的数据为准。`.split(
          "\n"
        ),
      upgradeGuidTexts:
        `ofskins的饰品升级符合公平性原则，10%的概率不代表10次必出，请选择合理的升级概率。
        升级取决于最后的落点值，可在多次尝试后选择你认为最合适的概率进行升级。`.split(
          "\n"
        ),

      openSkinDialog,
      upgrade,
      reset,
      handleUpgradeSkin(skin: SkinItem) {
        if (!upgradeSkin.value) {
          rate.value = 20;
        }
        isShowSkinDialog.value = false;
        upgradeSkin.value = skin;
      },
      handleClickButton() {
        if (!upgradeProfitRate.value) {
          getUpgradeProfitRate().then(() => {
            openSkinDialog();
          });
        } else {
          openSkinDialog();
        }
      },
      handleCloseResultDialog() {
        isShowResultDialog.value = false;
      },
      handleToTopHistory() {
        router.push("/top/history");
      },
      changeRate() {
        let n = Number(coins.value);
        if (!n) {
          ElMessage.warning("请输入正确的数字");
          return;
        }
        const skin = upgradeSkin.value;
        if (!skin) {
          ElMessage.warning("未选择饰品");
          return;
        }

        if (n < minCoins.value) {
          coins.value = n = minCoins.value;
        } else if (n > maxCoins.value) {
          coins.value = n = maxCoins.value;
        }

        rate.value = getRateByCoins(n);
      },
      changeAnimationFlag,
    };
  },

  components: {
    SkinDialog,
    ResultDialog,
    CompassBox,
  },
});
</script>

<style lang="scss">
$color: #7668ca;

.el-slider__bar {
  background-color: $color !important;
}
.el-slider__button {
  border-color: #fff !important;
  background-color: $color !important;
}
.el-slider__runway {
  background-color: #d8d8d8 !important;
}
.el-slider__stop {
  background-color: transparent !important;
}

.frame {
  .el-input__inner {
    background: #000;
    border: none;
    color: #fff;
  }
}
</style>
<style scoped lang="scss">
.upgrade-title {
  transform: translateY(-100%);
  z-index: 10;
  position: relative;

  .upgrade-title-img {
    width: 140px;
  }

  .tip {
    color: #fff;
    display: flex;
    align-items: center;
    position: absolute;
    top: 50%;
    right: 150px;
    transform: translateY(-50%);
    cursor: pointer;

    &:hover {
      .hot-to-play {
        display: block;
      }
    }

    img {
      width: 12px;
      margin-right: 6px;
    }

    .hot-to-play {
      position: absolute;
      text-align: left;
      width: 350px;
      left: 0;
      bottom: 0;
      transform: translate(-100%, 100%);
      background: #363638;
      padding: 20px;
      box-sizing: border-box;
      display: none;

      p {
        margin-bottom: 10px;

        &:last-child {
          margin-bottom: 0;
        }
      }
    }
  }
  .tipHis{
    right: 50px;
  }
}

.upgrade-box {
  width: 1296px;
  height: 713px;
  background: url(@/static/img/top/frame.png);
  background-size: 100% 100%;
  margin: 130px auto 0 auto;
}

.frame {
  position: relative;

  .frame-content {
    display: flex;
    height: 416px;
  }
}

.top-skin {
  width: 348px;
  height: 384px;
  background-image: url(@/static/img/top/stage.png);
  position: relative;
  margin-top: 16px;

  .upgrade-skin {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    text-align: center;

    img {
      width: 90%;
    }

    .bac-icon {
      width: 45%;
      height: 45%;
      position: absolute;
      z-index: -1;
      top: 2.4rem;
      left: 50%;
      transform: translateX(-50%);
      border-radius: 50%;

      .bac {
        position: absolute;
        top: 50%;
        left: 50%;
        transform: translate(-50%, -50%);
        width: 0px;
        height: 0px;
        border-radius: 50%;
        z-index: 0;
      }

      img {
        z-index: 1;
        position: relative;
        width: 100%;
        transform: scale(2);
        opacity: 0.8;
      }
    }
  }

  .upgrade-btn {
    position: absolute;
    left: 50%;
    bottom: 16px;
    transform: translateX(-50%);
  }
}

.top-skin:first-child {
  margin-left: 96px;
}

.top-skin-text {
  color: #fff;
  font-size: 19px;
  position: absolute;
  top: 122px;
  text-align: center;
  width: 100%;
}

.top-skin-button {
  width: 103px;
  height: 101px;
  position: absolute;
  top: 165px;
  left: 50%;
  transform: translate(-50%, 0);
}

.top-skin-button.btn-add {
  background-image: url(@/static/img/top/add.png);
  cursor: pointer;
}

.top-skin-button.btn-unknow {
  background-image: url(@/static/img/top/question.png);
}

.rate-wrapper {
  width: 800px;
  margin: 0 auto;
  font-size: 14px;

  .rate-text {
    display: flex;
    justify-content: space-between;

    > div {
      flex: 1;

      span:first-child {
        text-indent: 20px;
      }
      span:last-child {
        text-indent: 10px;
      }

      &:first-child {
        span:first-child {
          &::before {
            content: "";
            width: 14px;
            height: 14px;
            border-radius: 50%;
            background: #7668ca;
            position: absolute;
            top: 50%;
            left: 0;
            transform: translate(0, -50%);
          }
        }
      }

      &:last-child {
        text-align: right;

        span:first-child {
          &::before {
            content: "";
            width: 14px;
            height: 14px;
            border-radius: 50%;
            background: #d8d8d8;
            position: absolute;
            top: 50%;
            left: 0;
            transform: translate(0, -50%);
          }
        }
      }
    }
  }

  span {
    position: relative;
    display: inline-block;
  }
}

.upgrade-guide {
  color: #fff;
  width: 100%;
  background: #36363c;
  padding: 20px;
  box-sizing: border-box;

  .upgrade-guide-title {
    text-align: center;
    color: #fff;
    font-size: 22px;
    margin-bottom: 16px;
    position: relative;

    .el-icon-close {
      position: absolute;
      right: 10px;
      top: 50%;
      transform: translateY(-50%);
      color: #fff;
      cursor: pointer;
      font-size: 26px;
    }
  }

  p {
    margin-bottom: 16px;

    &:last-child {
      margin-bottom: 0;
    }
  }
}

.top-setting {
  .upgrade-button {
    text-decoration: underline;
    cursor: pointer;
  }

  > * {
    margin-right: 6px;

    &:last-child {
      margin-right: 0;
    }
  }
}

.compass-box-mobile {
  display: none;
}

.upgrade-bottom {
  display: flex;
  justify-content: center;
}

@media screen and (max-width: 768px) {
  .upgrade-box {
    width: 100%;
    height: auto;
    background-position: center center;
    padding-bottom: 160px;
    background-size: cover;

    .frame-content {
      margin-top: -66px;
      height: auto;
    }

    .top-skin {
      width: 50%;
      height: 200px;
      margin-left: 0;
      background-size: 100% 100%;

      .top-skin-text {
        top: 50px;
        font-size: 13px;
      }

      .top-skin-button {
        width: 50px;
        height: 50px;
        background-size: cover;
        top: 85px;
      }
    }
  }

  .compass-box-mobile {
    display: flex;
    justify-content: center;
  }

  .compass-box-pc {
    display: none;
  }

  .rate-wrapper {
    width: 90%;
  }

  .upgrade-bottom {
    flex-direction: column;
    align-items: center;

    > * {
      margin-top: 10px;
      margin-left: 0 !important;
      margin-right: 0 !important;
    }
  }

  .tip {
    right: 10px !important;
    .hot-to-play {
      width: 300px !important;
      transform: translate(-80%, 100%) !important;
    }
  }
  .tipHis{
    right: 80px!important;
  }
}
</style>
